package edu.nyp.multilayer_positioningsystem;

import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptor;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.GroundOverlay;
import com.google.android.gms.maps.model.GroundOverlayOptions;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.Polygon;
import com.google.android.gms.maps.model.PolygonOptions;

import com.skyhookwireless.wps.*;

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;

import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.telephony.TelephonyManager;
import android.telephony.gsm.GsmCellLocation;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MapActivity extends FragmentActivity {
	
	/** declare Variables */
	// Block S Polygon
	Polygon blockSPolygon;
	PolygonOptions blockSOptions;
	
	// Block S Lift Polygon
	Polygon blockSLiftPolygon;
	PolygonOptions blockSLiftOptions;
	
	
	
	BitmapDescriptor image;
	LatLng southwest = new LatLng(1.37863,103.848269);
	LatLng northeast = new LatLng(1.379512,103.848843);
	LatLngBounds bounds = new LatLngBounds(southwest,northeast);
	GroundOverlay groundOverlay;
	Bitmap bitmapImage;
	private static final String fileLocation = "/MultiLayer_PositioningSystem/res/drawable-hdpi/BlockS_Level1_FloorPlanV1.jpg";
	
	
	
	LocationManager locationManager;
	LocationListener gpsLocationListener;
	LocationListener wifiLocationListener;
	LocationListener locationListener;
	
	Marker gpsMarker;
	Marker wifiMarker;
	Marker calMarker;
	boolean existGpsMarker = false;
	boolean existWifiMarker = false;
	boolean existCalMarker = false;
	
	private static final String TAG = "MapActivity";
	GoogleMap googleMap;
	SupportMapFragment supportMap;
	
	double wifiAcc;
	double gpsAcc;
	double gpsLat;
	double gpsLng;
	double wifiLat;
	double wifiLng;
	double calLat;
	double calLng;
	double calAcc;
	double actualLat;
	double actualLng;
	double wifiDistanceActual;
	double gpsDistanceActual;
	double calDistanceActual;
	double wifiDistanceGps;
	
	 
	@Override
	protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.map);
        
        // Find View of the Map 
        supportMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map));
        googleMap = supportMap.getMap();
        
        // Set Map View to Hybrid mode (Satellite + Normal)
        /**googleMap.setMapType(googleMap.MAP_TYPE_HYBRID);*/
        
        
        
    /** Try to put image of indoor map into google Map using GroundOverlay */
        // Getting an image
        
        //bitmapImage = BitmapFactory.decodeFile(R.drawable.ic_launcher);
        //image = BitmapDescriptorFactory.fromBitmap(bitmapImage);
        //image = BitmapDescriptorFactory.fromFile(fileLocation);
        
        /** image = BitmapDescriptorFactory.defaultMarker();
        
        // Add a ground overlay with 50% transparency
        groundOverlay = googleMap.addGroundOverlay(new GroundOverlayOptions()
        	.image(image)
        	.positionFromBounds(bounds)
        	);*/
        
        
        
        
     /** Try to put indoor map into google Map using Polygons */
        // For Block S
        // Instantiates a new polygon object and adds points in a counterclockwise order to define a rectangle
       blockSOptions = new PolygonOptions()
       		// Boundaries of Block S
        	.add(	new LatLng(1.379401,103.848132),
        			new LatLng(1.378639,103.84826),
        			new LatLng(1.378758,103.848964),
        			new LatLng(1.379518,103.848839),
        			new LatLng(1.379401,103.848132));
        // Set the rectangle's stroke color to red
        blockSOptions.strokeColor(Color.RED);
        
        
        // For Block S Lift
        // Instantiates a new polygon object and adds points in a counterclockwise order to define a rectangle
        blockSLiftOptions = new PolygonOptions()
        		// Boundaries of Block S
         	.add(	new LatLng(1.379076,103.848193),
         			new LatLng(1.378972,103.84821),
         			new LatLng(1.378985,103.848301),
         			new LatLng(1.379088,103.848283),
         			new LatLng(1.379076,103.848193));
         // Set the rectangle's stroke color to red
         blockSLiftOptions.strokeColor(Color.BLACK);
        
       
        
        
        
        
        // Finally,Get back the mutable Polygon and set to invisible first
        // For Block S
        blockSPolygon = googleMap.addPolygon(blockSOptions);
        blockSPolygon.setVisible(false);
        // For Block S lift
        blockSLiftPolygon = googleMap.addPolygon(blockSLiftOptions);
        blockSLiftPolygon.setVisible(false);
        	
       
        
        
        
        
	     // Get Current Camera Location
	        CameraPosition currentCameraPosition = googleMap.getCameraPosition();
	        LatLng currentCameraPositionLatLng = currentCameraPosition.target;
	        
	        // Add Marker based on location result
	        googleMap.addMarker(new MarkerOptions()
	        	.position(new LatLng(1.379524,103.848843))
	        	//.position(currentCameraPositionLatLng)
	        	.title("MyActualLocation")
	        );
	        
	        
        // Acquire a reference to the system Location Manager for GPS and WIFI
  		locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
  		
  		locationListener = new LocationListener() {
  			@Override
			public void onLocationChanged(Location location) {
	    	// Called when a new location is found by the network location provider.
  			// Generate location based on provider
			     if(location.getProvider().contains("gps")) {
			    	 // clear existing marker for gps
			    	 if(existGpsMarker) {
			    		 gpsMarker.remove();
			    	 }
		 		     gpsNewLocation(location);
			     }
			     if(location.getProvider().contains("network")) {
			    	// clear existing marker for wifi
			    	 if(existWifiMarker) {
			    		 wifiMarker.remove();
			    	 }
		 		     wifiNewLocation(location);
			     }
			// Generate location based on Calculation
			  // clear existing marker for calculated
			     if(existCalMarker) {
			    	 calMarker.remove();
			     }
			     calNewLocation(gpsLat,gpsLng,gpsAcc,wifiLat,wifiLng,wifiAcc);
		     
 		    }

 		    @Override
			public void onStatusChanged(String provider, int status, Bundle extras) {}

 		    @Override
			public void onProviderEnabled(String provider) {}

 		    @Override
			public void onProviderDisabled(String provider) {}
 		  };
 		  
 		// Request Location
	  		
 		locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
 		locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
 		
	}
	
	protected void calNewLocation(double gpsLat, double gpsLng, double gpsAcc,
			double wifiLat, double wifiLng, double wifiAcc) {
		// TODO Auto-generated method stub
		Log.d(TAG, "onLocationChanged with calculation ");
		
		// calculate distance of gps from Wifi
     	double gpsWifiLatPow = Math.pow((gpsLat - wifiLat), 2);
     	double gpsWifiLngPow = Math.pow((gpsLng - wifiLng), 2);
     	double combineGpsWifiPow = gpsWifiLatPow + gpsWifiLngPow;
     	wifiDistanceGps =  Math.sqrt(combineGpsWifiPow) * 1.1 * Math.pow(10,5);
     	
     	// Calculation of accuracy of calculated position
     	calAcc = Math.sqrt( 1/( (1/(Math.pow(gpsAcc, 2)) + (1/(Math.pow(gpsAcc, 2))) ) ) );
		
		//if 2 * calAcc > wifiDistanceGps
     	if((2 * calAcc) > wifiDistanceGps)
     	{
     	// if gpsAcc > wifiAcc
			if(gpsAcc > wifiAcc)
			{
				calLat = ( ( ( 1/(Math.pow(gpsAcc, 2)) ) / ( ( 1/(Math.pow(gpsAcc, 2))) + ( 1/(Math.pow(wifiAcc, 2))) ) ) * (gpsLat) ) + ( ( ( 1/(Math.pow(wifiAcc, 2)) ) / ( ( 1/(Math.pow(gpsAcc, 2))) + ( 1/(Math.pow(wifiAcc, 2))) ) ) * (wifiLat) );
	     		calLng = ( ( ( 1/(Math.pow(gpsAcc, 2)) ) / ( ( 1/(Math.pow(gpsAcc, 2))) + ( 1/(Math.pow(wifiAcc, 2))) ) ) * (gpsLng) ) + ( ( ( 1/(Math.pow(wifiAcc, 2)) ) / ( ( 1/(Math.pow(gpsAcc, 2))) + ( 1/(Math.pow(wifiAcc, 2))) ) ) * (wifiLng) );
			}
			else
			{
				calLat = ( ( ( 1/(Math.pow(wifiAcc, 2)) ) / ( ( 1/(Math.pow(gpsAcc, 2))) + ( 1/(Math.pow(wifiAcc, 2))) ) ) * (gpsLat) ) + ( ( ( 1/(Math.pow(gpsAcc, 2)) ) / ( ( 1/(Math.pow(gpsAcc, 2))) + ( 1/(Math.pow(wifiAcc, 2))) ) ) * (wifiLat) );
	     		calLng = ( ( ( 1/(Math.pow(wifiAcc, 2)) ) / ( ( 1/(Math.pow(gpsAcc, 2))) + ( 1/(Math.pow(wifiAcc, 2))) ) ) * (gpsLng) ) + ( ( ( 1/(Math.pow(gpsAcc, 2)) ) / ( ( 1/(Math.pow(gpsAcc, 2))) + ( 1/(Math.pow(wifiAcc, 2))) ) ) * (wifiLng) );
			}
     	}
		
		// else
     	else
     	{
     		calLat = ( ( ( 1/(Math.pow(gpsAcc, 2)) ) / ( ( 1/(Math.pow(gpsAcc, 2))) + ( 1/(Math.pow(wifiAcc, 2))) ) ) * (gpsLat) ) + ( ( ( 1/(Math.pow(wifiAcc, 2)) ) / ( ( 1/(Math.pow(gpsAcc, 2))) + ( 1/(Math.pow(wifiAcc, 2))) ) ) * (wifiLat) );
     		calLng = ( ( ( 1/(Math.pow(gpsAcc, 2)) ) / ( ( 1/(Math.pow(gpsAcc, 2))) + ( 1/(Math.pow(wifiAcc, 2))) ) ) * (gpsLng) ) + ( ( ( 1/(Math.pow(wifiAcc, 2)) ) / ( ( 1/(Math.pow(gpsAcc, 2))) + ( 1/(Math.pow(wifiAcc, 2))) ) ) * (wifiLng) );
     	}
		
		
		LatLng calLatLng = new LatLng(calLat,calLng);
		
		// Add Marker based on location result
        calMarker = googleMap.addMarker(new MarkerOptions()
        	.position(calLatLng)
        	.title("NYPCurrentLocation")
        	.snippet("Location Description not available yet..\n" + "Lat: " + calLat + " Long: " + calLng )
        );
        existCalMarker = true;
        
        /** If NypCurrentLoc is in block S, Show the indoor map's Polygons.*/
        // The 4 boundaries in this if statement is a bigger and upright square boundary,
        // which does not only contains Block S, a slanted square boundary shown on google map
        // but also contains 4 excess triangles outside block S which there is a need to remove it.
        if(calLat >= 1.378639 && calLat <= 1.379518 && calLng >= 103.848132 && calLng <= 103.848964 )
        {
        	// Still not set to Block S Boundaries, need to remove the boundaries of the 4 triangles.
        	// If cannot find the solution to remove boundaries of the 4 triangles, an alternative is
        	// keep the 4 triangles such that if a user is near block S, the polygons will appear.
        	blockSPolygon.setVisible(true);
        	blockSLiftPolygon.setVisible(true);
        }
        else{
        	blockSPolygon.setVisible(false);
        	blockSLiftPolygon.setVisible(false);
        }
       
        
		
	}

	protected void gpsNewLocation(Location location) {
		// TODO Auto-generated method stub
    	Log.d(TAG, "onLocationChanged with location " + location.toString());
     	
 	/** Get Lat and Long from location and convert to LatLng format to be used to update marker */
     	// Get lat and Long and convert to LatLng format in order to animate camera
     	gpsLat = location.getLatitude();
     	gpsLng = location.getLongitude();
     	gpsAcc = location.getAccuracy();
     	LatLng gpsLatLng = new LatLng(gpsLat,gpsLng);
     	
     	/*// Animate camera to location
     	CameraPosition gpsCameraPosition = new CameraPosition.Builder()    
     		.target(gpsLatLng)      
     		// Sets the center of the map to gpsLatLng    
     		.zoom(18)                   
     		// Sets the zoom    
     		.bearing(90)                
     		// Sets the orientation of the camera to east    
     		.tilt(30)                   
     		// Sets the tilt of the camera to 30 degrees    
     		.build();                   
     	// Creates a CameraPosition from the buildermap.
     	googleMap.animateCamera(CameraUpdateFactory.newCameraPosition(gpsCameraPosition));*/
     	  
        // Add Marker based on location result
        gpsMarker = googleMap.addMarker(new MarkerOptions()
        	.position(gpsLatLng)
        	.title("MyGPSCurrentLocation")
        	.snippet("Location Description not available yet..\n" + "Lat: " + gpsLat + " Long: " + gpsLng )
        );
        
        existGpsMarker = true;
     	
	}
    protected void wifiNewLocation(Location location) {
		// TODO Auto-generated method stub
    	Log.d(TAG, "onLocationChanged with location " + location.toString());
     	
    	// Get lat and Long and convert to LatLng format in order to animate camera
     	wifiLat = location.getLatitude();
     	wifiLng = location.getLongitude();
     	wifiAcc = location.getAccuracy();
     	LatLng wifiLatLng = new LatLng(wifiLat,wifiLng);
     	
     	// Animate camera to location
     	/*CameraPosition wifiCameraPosition = new CameraPosition.Builder()    
     		.target(wifiLatLng)      
     		// Sets the center of the map to gpsLatLng    
     		.zoom(18)                   
     		// Sets the zoom    
     		.bearing(90)                
     		// Sets the orientation of the camera to east    
     		.tilt(30)                   
     		// Sets the tilt of the camera to 30 degrees    
     		.build();                   
     	// Creates a CameraPosition from the buildermap.
     	googleMap.animateCamera(CameraUpdateFactory.newCameraPosition(wifiCameraPosition));*/
     	
        // Add Marker based on location result
        wifiMarker = googleMap.addMarker(new MarkerOptions()
        	.position(wifiLatLng)
        	.title("MyWiFiCurrentLocation")
        	.snippet("Location Description not available yet..\n" + "Lat: " + wifiLat + " Long: " + wifiLng )
        );
        
        existWifiMarker = true;
        
        
     	
	}
	
}
	


